package com.nobuyme.box.downUpdata;

/**
 * Created by Administrator on 2017/3/1.
 */


import android.text.TextUtils;
import android.util.Log;

import org.json.JSONObject;

import java.io.File;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Request.Builder;
import okhttp3.RequestBody;
import okhttp3.Response;


/**
 * @author Administrator
 *         <p>
 *         <p>
 *         如果要取得返回数据的header，可以在header.headers()，默认返回的字符串就是UTF-8-response.body().string()，get
 *         添加权限
 *         <uses-permission android:name="android.permission.INTERNET"/>
 *         //下面这些事使用到缓存的时候需要用的
 *         <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
 *         <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
 *         <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 */
public class OkHttpUtil {

    public static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    private static final String CHARSET_NAME = "UTF-8";
    //懒汉式
    private static OkHttpClient mOkHttpClient;
    //缓存路径
    public static final String FilePath = "OKHTTPCacheFile";
    //缓存大小
    public static final int cacheSize = 30 * 1024 * 1024; // 10 MiB
    //链接缓存时间    单位秒
    private static final int conectTimeout = 8;
    //写入缓存时间    单位秒
    private static final int writeTimeout = 8;
    //读取缓存时间    单位秒
    private static final int readTimeout = 8;


    private OkHttpUtil() {
    }

    //初始化
    public static void initOkHttpUtil() {
        if (mOkHttpClient == null) {
            synchronized (OkHttpUtil.class) {
                if (mOkHttpClient == null) {
                    File cacheDirectory = new File(FilePath);
                    Cache cache = new Cache(cacheDirectory, cacheSize);
                    mOkHttpClient = new OkHttpClient().newBuilder()
                            .cache(cache)       //最好不要更改cache目录
                            .connectTimeout(conectTimeout, TimeUnit.SECONDS)//设置相应时间
                            .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                            .readTimeout(readTimeout, TimeUnit.SECONDS)
                            .retryOnConnectionFailure(false)            //错误重连
                            .build();
                }
            }
        }
    }


    //TODO 克隆一个client，更改链接时间等参数设置

    /**
     * 异步请求数据，有回调参数
     *
     * @param url
     * @param callback
     */
    public static void get(String url, CallbackUTF8 callback) {
        try {
            Request request = new Request.Builder()
                    .url(url)
                    .tag(url)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(request);
            newCall.enqueue(callback);
            Log.i("OKHttpUtil", "urls = " + url);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
    }
    public static String getSync(String url) {
        String responseStr = null;
        try {
            Request request = new Request.Builder()
                    .url(url)
                    .tag(url)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(request);
            Response response = newCall.execute();
            Log.i("OKHttpUtil", "urls = " + url);
            responseStr = response.body().string();
            responseStr = response.isSuccessful() ? responseStr : null;
        } catch (Exception e) {
            Log.e("okHttpUtil","e.getMessage()");
            responseStr = null;
        }
        return responseStr;
    }

    /**
     * url参数较多时，可以使用map来拼接参数
     *
     * @param url
     * @param params
     * @param callback
     */
    public static void get(String url, Map<String, Object> params, CallbackUTF8 callback) {
        String urls = buildParams(url, params);
        try {
            Request request = new Request.Builder()
                    .url(urls)
                    .tag(url)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(request);
            newCall.enqueue(callback);
            Log.i("OKHttpUtil", "urls = " + urls);
        } catch (Exception e) {
            callback.onFailure(e);
        }
    }


    /**
     * 带header的get请求 如果url参数比较多，可以传递map，直观点
     *
     * @param urls
     * @param params
     * @param headerMap
     * @param callback
     */
    public static void get(String urls, Map<String, Object> headerMap, Map<String, Object> params, CallbackUTF8 callback) {
        String url = buildParams(urls, params);
        Builder builder = new Request.Builder();
        if (headerMap != null)
            for (String str : headerMap.keySet()) {
                builder.addHeader(str, headerMap.get(str).toString());
            }
        try {
            Request request = builder
                    .url(url)
                    .tag(urls)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(request);
            newCall.enqueue(callback);
            Log.i("OKHttpUtil", "urls = " + urls);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
        return;
    }


    public static void post(String url, Map<String, Object> headerParams,
                            Map<String, Object> params, CallbackUTF8 callback) {
        try {
            okhttp3.FormBody.Builder builder = new FormBody.Builder();
            for (String key : params.keySet()) {
                builder.add(key, params.get(key).toString());
            }
            RequestBody body = builder.build();

            Request.Builder builder1 = new Request.Builder();

            builder1.post(body).url(url).tag(url);

            if (headerParams != null) {
                for (String key : headerParams.keySet()) {
                    builder1.addHeader(key, headerParams.get(key).toString());
                }
            }

            Request requeset = builder1.build();

            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(requeset);
            newCall.enqueue(callback);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
        return;
    }

    /**
     * 简单的post请求
     *
     * @param url
     * @param params
     * @param callback
     */
    public static void post(String url, Map<String, Object> params, CallbackUTF8 callback) {
        try {
            okhttp3.FormBody.Builder builder = new FormBody.Builder();
            for (String key : params.keySet()) {
                builder.add(key, params.get(key).toString());
            }
            RequestBody body = builder.build();
            Request requeset = new Request.Builder()
                    .post(body)
                    .url(url)
                    .tag(url)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(requeset);
            newCall.enqueue(callback);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
        return;
    }


    /**
     * 简单的post请求
     *
     * @param url
     * @param jsonArray
     * @param callback
     */
    public static void postJson(String url, Map<String, Object> headerParams, JSONObject jsonArray, CallbackUTF8 callback) {
        MediaType JSON = MediaType
                .parse("application/json; charset=utf-8");
        try {
            RequestBody body = RequestBody.create(JSON, jsonArray.toString());

            Builder builder = new Builder();

            builder.url(url)
                    .tag(url)
                    .post(body);

            if (headerParams != null) {
                for (String key : headerParams.keySet()) {
                    builder.addHeader(key, headerParams.get(key).toString());
                }
            }

            Request requeset = builder.build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }

//            File cacheDirectory = new File(OkHttpUtil.FilePath);
//            Cache cache = new Cache(cacheDirectory, OkHttpUtil.cacheSize);
//            OkHttpClient mOkHttpClient = new OkHttpClient().newBuilder()
//                    .cache(cache)       //最好不要更改cache目录
//                    .connectTimeout(10, TimeUnit.SECONDS)//设置相应时间
//                    .writeTimeout(10, TimeUnit.SECONDS)
//                    .readTimeout(10, TimeUnit.SECONDS)
//                    .retryOnConnectionFailure(false)            //错误重连
//                    .build();

            Call newCall = mOkHttpClient.newCall(requeset);
            newCall.enqueue(callback);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
        return;
    }

    /**
     *
     * @param url
     * @param bodyStr
     * @param callback
     */
    public static void postBody(String url, Map<String, Object> headerParams, String bodyStr, CallbackUTF8 callback) {
        MediaType JSON = MediaType
                .parse("application/json; charset=utf-8");
        try {
            RequestBody body = RequestBody.create(JSON, bodyStr);
            Builder builder = new Builder();

            builder.url(url)
                    .tag(url)
                    .post(body);

            if (headerParams != null) {
                for (String key : headerParams.keySet()) {
                    builder.addHeader(key, headerParams.get(key).toString());
                }
            }

            Request requeset = builder.build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }

//            File cacheDirectory = new File(OkHttpUtil.FilePath);
//            Cache cache = new Cache(cacheDirectory, OkHttpUtil.cacheSize);
//            OkHttpClient mOkHttpClient = new OkHttpClient().newBuilder()
//                    .cache(cache)       //最好不要更改cache目录
//                    .connectTimeout(10, TimeUnit.SECONDS)//设置相应时间
//                    .writeTimeout(10, TimeUnit.SECONDS)
//                    .readTimeout(10, TimeUnit.SECONDS)
//                    .retryOnConnectionFailure(false)            //错误重连
//                    .build();

            Call newCall = mOkHttpClient.newCall(requeset);
            newCall.enqueue(callback);
            return;
        } catch (Exception e) {
            callback.onFailure(e);
        }
        return;
    }

    /**
     * 同步的post请求
     *
     * @param url
     * @param bodyStr
     */
    public static String postBodysync(String url, String bodyStr) {
        MediaType JSON = MediaType
                .parse("application/json; charset=utf-8");
        String responseStr = null;
        try {
            RequestBody body = RequestBody.create(JSON, bodyStr);
            Builder builder = new Builder();

            builder.url(url)
                    .tag(url)
                    .post(body);


            Request requeset = builder.build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }

//            File cacheDirectory = new File(OkHttpUtil.FilePath);
//            Cache cache = new Cache(cacheDirectory, OkHttpUtil.cacheSize);
//            OkHttpClient mOkHttpClient = new OkHttpClient().newBuilder()
//                    .cache(cache)       //最好不要更改cache目录
//                    .connectTimeout(10, TimeUnit.SECONDS)//设置相应时间
//                    .writeTimeout(10, TimeUnit.SECONDS)
//                    .readTimeout(10, TimeUnit.SECONDS)
//                    .retryOnConnectionFailure(false)            //错误重连
//                    .build();


            Call newCall = mOkHttpClient.newCall(requeset);
            Response response = newCall.execute();
            responseStr = response.body().string();
            responseStr = response.isSuccessful() ? responseStr : null;
        } catch (Exception e) {
            Log.e("okHttpUtil","e.getMessage()");
            responseStr = null;
        }
        return responseStr;
    }


    /**
     * 提交文件
     *
     * @param url
     * @param file
     * @param callback
     */
    public void postFile(String url, File file, CallbackUTF8 callback) {
        final MediaType MEDIA_TYPE_MARKDOWN
                = MediaType.parse("text/x-markdown; charset=utf-8");
        Request request = new Request.Builder()
                .url(url)
                .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
                .build();
        if (mOkHttpClient == null) {
            initOkHttpUtil();
        }
        Call newCall = mOkHttpClient.newCall(request);
        newCall.enqueue(callback);
    }


    /**
     * 下载文件
     *
     * @param url
     * @param params
     * @param callBackFileStream
     */
    public static void postDownFile(String url, Map<String, Object> params, CallBackFileStream callBackFileStream) {
        try {
            okhttp3.FormBody.Builder builder = new FormBody.Builder();
            try{
                for (String key : params.keySet()) {
                    builder.add(key, params.get(key).toString());
                }
            }catch (Exception e){

            }
            RequestBody body = builder.build();
            Request requeset = new Request.Builder()
//                    .post(body)
                    .url(url)
//                    .tag(url)
                    .build();
            if (mOkHttpClient == null) {
                initOkHttpUtil();
            }
            Call newCall = mOkHttpClient.newCall(requeset);
            newCall.enqueue(callBackFileStream);
            return;
        } catch (Exception e) {
            callBackFileStream.onFailure(e);
        }
        return;
    }


    /**
     * 拼接url参数
     *
     * @param url
     * @param params
     * @return
     */
    public static String buildParams(String url, Map<String, Object> params) {
        if (TextUtils.isEmpty(url)) {
            return url;
        }
        if (params == null || params.size() == 0) {
            return url;
        }
        url += "?";
        Set<String> keySet = params.keySet();
        Iterator<String> itr = keySet.iterator();
        while (itr.hasNext()) {
            String key = itr.next();
            url += key + "=" + params.get(key) + "&";
        }
        url = url.substring(0, url.length() - 1);
        return url;
    }

    /**
     * 取消网络请求
     *
     * @param call
     */
    public static void disCall(Call call) {
        if (call != null) {
            Log.e("OKHttpUtil", " 取消网络请求");
            call.cancel();
        }
    }

    public static void cancelCallWithTag() {
        if (mOkHttpClient == null) {
            Log.e("OKHttpUtils", "cancelCallWithTag->mOkHttpClient == null");
            return;
        }
        mOkHttpClient.dispatcher().cancelAll();
    }

    public static void cancelCallWithTag(String tag) {
        // A call may transition from queue -> running. Remove queued Calls first.
        if (mOkHttpClient == null) {
            Log.e("OKHttpUtils", "cancelCallWithTag->mOkHttpClient == null");
            return;
        }
        for (Call call : mOkHttpClient.dispatcher().queuedCalls()) {
            if (call.request().tag().equals(tag))
                call.cancel();
        }
        for (Call call : mOkHttpClient.dispatcher().runningCalls()) {
            if (call.request().tag().equals(tag))
                call.cancel();
        }
    }

    public static void cancelCallWithTag(OkHttpClient client, String tag) {
        // A call may transition from queue -> running. Remove queued Calls first.
        for (Call call : client.dispatcher().queuedCalls()) {
            if (call.request().tag().equals(tag))
                call.cancel();
        }
        for (Call call : client.dispatcher().runningCalls()) {
            if (call.request().tag().equals(tag))
                call.cancel();
        }
    }

}
